package com.hitqz.robot.biz.config;

/**
 * @author xupkun
 * @date 2024/12/1
 */

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.FileAppender;
import com.hitqz.robot.biz.websocket.endpoint.SubscriptionLogEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 读取日志文件最后的数据
 */
@Slf4j
public class LogTailer {

    public static boolean hasPush = false;
    private static final ThreadPoolExecutor networkExecutor = new ThreadPoolExecutor(
            10,               // 核心线程数
            20,              // 最大线程数
            60L,             // 非核心线程存活时间
            TimeUnit.SECONDS, // 时间单位
            new LinkedBlockingQueue<>(50),  // 阻塞队列
            Executors.defaultThreadFactory(), // 默认的线程工厂
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略：提交任务的线程执行任务
    );

    public static void readLogTailer() {
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        // 获取名为"FILE"的Appender（假设你的日志输出到名为FILE的Appender）
        FileAppender fileAppender = (FileAppender) loggerContext.getLogger("ROOT").getAppender("info");
        if (fileAppender!= null) {
            String logFilePath =System.getProperty("user.dir") + File.separator + fileAppender.getFile();
            Path logPath = Paths.get(logFilePath);
            log.info("读取日志文件的地址是：" + logPath);
            networkExecutor.execute(()-> {
                try {
                    long lastModified = Files.getLastModifiedTime(logPath).toMillis();
                    WatchService watcher = FileSystems.getDefault().newWatchService();
                    WatchKey key =  logPath.getParent().register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
                    while (true) {
                        WatchKey wk = watcher.poll(1, TimeUnit.MINUTES);
                        if (wk != null) {
                            for (WatchEvent<?> event : wk.pollEvents()) {
                                WatchEvent.Kind<?> kind = event.kind();
                                if (kind == StandardWatchEventKinds.OVERFLOW) {
                                    continue;
                                }
                                if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
                                    long newModified = Files.getLastModifiedTime(logPath).toMillis();
                                    if (newModified > lastModified) {
                                        lastModified = newModified;
                                        try (BufferedReader reader = Files.newBufferedReader(logPath)) {
                                            String lastLine = "";
                                            try (RandomAccessFile file = new RandomAccessFile(logPath.toFile().getAbsolutePath(), "r")) {
                                                long fileLength = file.length() - 1;
                                                StringBuilder sb = new StringBuilder();
                                                for (long filePointer = fileLength; filePointer >= 0; filePointer--) {
                                                    file.seek(filePointer);
                                                    int readByte = file.readByte();
                                                    if (readByte == 0xA) {
                                                        if (filePointer == fileLength) {
                                                            continue;
                                                        }
                                                        break;
                                                    } else if (readByte == 0xD) {
                                                        if (filePointer == fileLength - 1) {
                                                            continue;
                                                        }
                                                        break;
                                                    }
                                                    sb.append((char) readByte);
                                                }
                                                lastLine = sb.reverse().toString();
                                                SubscriptionLogEndpoint.broadcast(
                                                        null,
                                                        "server",
                                                        removeAnsiEscapes(lastLine));
                                                new String(removeAnsiEscapes(lastLine).getBytes(), StandardCharsets.UTF_8);
                                            } catch (IOException e) {
                                                e.printStackTrace();
                                            }
                                        }
                                    }
                                }
                            }

                            wk.reset();
                        }
                    }
                }catch (Exception e) {
                    log.info("文件读取失败" + e.getMessage());
                }
            });
        }
    }


    public static void pushNow(String randomId) {
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        // 获取名为"FILE"的Appender（假设你的日志输出到名为FILE的Appender）
        FileAppender fileAppender = (FileAppender) loggerContext.getLogger("ROOT").getAppender("info");
        if (fileAppender!= null) {
            networkExecutor.execute(()-> {
                try {
                    String logFilePath = System.getProperty("user.dir") + File.separator + fileAppender.getFile();
                    Path logPath = Paths.get(logFilePath);
                    try (BufferedReader reader = Files.newBufferedReader(logPath)) {
                        String line;
                        while ((line = reader.readLine()) != null) {
                            try {
                                SubscriptionLogEndpoint.broadcast(
                                        Integer.valueOf(randomId),
                                        "server",
                                        removeAnsiEscapes(line));
                            }catch (Exception e) {
                            }
                        }
                    }
                } catch (Exception e) {
                    log.info("Exception：" + e.getMessage());
                }
            });
            if (!LogTailer.hasPush) {
                LogTailer.readLogTailer();
                LogTailer.hasPush = true;
            }
        }
    }
    private static String removeAnsiEscapes(String input) {
        if (input == null) {
            return null;
        }
        return input.replaceAll("\\u001B\\[[;\\d]*[a-zA-Z]", "");
    }




}
